#pragma once

#include "../database.hpp"
#include "../except.hpp"
#include "../libs/easylog.h"

namespace pharmacy_server
{
    class AlertModel
    {
    public:
        std::vector<int> check_stock_alerts()
        {
            std::vector<int> alerts;

            easymysql::result res = easymysql::executer(database::instance())(R"(
SELECT id, name, stock, threshold FROM medicines
            )");

            std::tuple<int, std::string, int, int> line;
            while (res.get<std::tuple<int, std::string, int, int>>(&line))
            {
                auto id = std::get<0>(line);
                auto name = std::get<1>(line);
                auto stock = std::get<2>(line);
                auto threshold = std::get<3>(line);

                if (stock < threshold)
                {
                    easylog::warn("Medicine {} (id: {}) is below the threshold. Current stock: {}, Threshold: {}", name, id, stock, threshold);
                    alerts.push_back(id);
                }
            }
            return alerts;
        }

        struct expired_info {
            int id;
            std::string purchase_date;
            std::string expired_date;
        };

        using expiry_result_type = std::pair<std::vector<expired_info>, std::vector<expired_info>>;

        expiry_result_type check_expiry()
        {
            std::vector<expired_info> already, soon;

            easymysql::result res = easymysql::executer(database::instance())(R"(
SELECT m.id, m.name, m.validity, po.purchase_date
    FROM medicines m
    JOIN purchase_records po ON m.name = po.medicine_name
            )");

            std::tuple<int, std::string, int, std::string> line;
            while (res.get<std::tuple<int, std::string, int, std::string>>(&line))
            {
                int id = std::get<0>(line);
                std::string name = std::get<1>(line);
                int validity = std::get<2>(line);

                time_t purchase_time = time_util::str2time(std::get<3>(line));
                time_t expired_time = purchase_time + validity * 24 * 60 * 60;

                time_t now = time_util::now();
                double diff = std::difftime(expired_time, now);

                if (diff < 0)
                {
                    std::string expired_date = time_util::time2str(expired_time);
                    std::string purchase_date = time_util::time2str(purchase_time);

                    easylog::warn("Medicine {} is expired. Expiry date: {}", name, time_util::time2str(expired_time));
                    already.push_back({id, purchase_date, expired_date });
                }
                else if (diff < 30 * 24 * 60 * 60) // 30 days
                {
                    std::string expired_date = time_util::time2str(expired_time);
                    std::string purchase_date = time_util::time2str(purchase_time);

                    easylog::warn("Medicine {} will expire soon. Expiry date: {}", name, expired_date);
                    soon.push_back({id, purchase_date, expired_date });
                }
            }

            return { already, soon };
        }
    };
}